package config

import (
	"fmt"
	"github.com/rs/zerolog/log"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"shyxy-model-agent/common/storage"
	"time"
)

type MysqlConfig struct {
	Datasource Datasource `json:"datasource"`
}

type Datasource struct {
	Host      string `json:"host"`
	Port      int    `json:"port"`
	DBName    string `json:"db_name"`
	Username  string `json:"username"`
	Password  string `json:"password"`
	Charset   string `json:"charset"`
	ParseTime bool   `json:"parse_time"`
	Loc       string `json:"loc"`
}

func (d *Datasource) dns() (string, error) {
	if d.Username == "" || d.Password == "" || d.Host == "" || d.DBName == "" || d.Port == 0 {
		return "", fmt.Errorf("missing required mysql config")
	}
	if d.Charset == "" {
		d.Charset = "utf8mb4"
	}
	if d.Loc == "" {
		d.Loc = "Local"
	}
	return storage.ToDNS(d.Username, d.Password, d.Host, d.DBName, d.Charset, d.Loc, d.Port, d.ParseTime), nil
}

func (mc *MysqlConfig) connect() (*gorm.DB, error) {
	dns, err := mc.Datasource.dns()
	if err != nil {
		return nil, err
	}
	db, err := gorm.Open(mysql.Open(dns), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to database: %w", err)
	}
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("failed to get database instance: %w", err)
	}
	// 设置连接池参数
	sqlDB.SetMaxIdleConns(20)
	sqlDB.SetMaxOpenConns(200)
	sqlDB.SetConnMaxLifetime(30 * time.Minute)
	sqlDB.SetConnMaxIdleTime(10 * time.Minute)

	return db, nil
}

func (mc *MysqlConfig) DB() (*gorm.DB, error) {
	maxRetries := 7
	baseDelay := time.Second
	maxDelay := 30 * time.Second
	for i := 0; i < maxRetries; i++ {
		db, err := mc.connect()
		if err == nil {
			return db, nil
		}
		delay := time.Duration(i+1) * baseDelay
		if delay > maxDelay {
			delay = maxDelay
		}
		log.Error().Msgf("failed to connect to database: %v, retrying in %v... (attempt %d/%d)",
			err, delay, i+1, maxRetries)
		time.Sleep(delay)
	}
	return mc.connect()
}
